﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Validation.cs" company="Radical Research Ltd">
//   Copyright (c) Radical Research Ltd. The MIT License (MIT)
// </copyright>
// <summary>
//   
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace RadicalResearch.MiniState
{
    using System.Security.Cryptography;

    /// <summary>
    /// Validation Helper Object
    /// </summary>
    public class Validation
    {
        #region Constants and Fields

        /// <summary>
        /// Byte value map for HexStringToByteArray.
        /// </summary>
        private static byte[] hexVal;

        /// <summary>
        /// Random number generator.
        /// </summary>
        private static RNGCryptoServiceProvider randomNumberGenerator;

        /// <summary>
        /// bytes used to salt HMAC hashes.
        /// </summary>
        private static byte[] validationKey;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the validation key bytes.
        /// </summary>
        public static byte[] ValidationKey
        {
            get
            {
                if (validationKey == null)
                {
                    byte[] buffer = new byte[0x20];
                    RandomNumberGenerator.GetBytes(buffer);
                    validationKey = buffer;
                }

                return validationKey;
            }
        }

        /// <summary>
        /// Gets the random number generator.
        /// </summary>
        private static RNGCryptoServiceProvider RandomNumberGenerator
        {
            get
            {
                if (randomNumberGenerator == null)
                {
                    randomNumberGenerator = new RNGCryptoServiceProvider();
                }

                return randomNumberGenerator;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Hashes data using the current ValidationKey.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
        /// <returns>HMAC hash of the specified data.</returns>
        public static byte[] HashData(byte[] buffer)
        {
            return HashData(buffer, ValidationKey);
        }

        /// <summary>
        /// Hashes data using the specified validation key.
        /// </summary>
        /// <param name="buffer">The buffer.</param>
        /// <param name="validationKey">The validation key.</param>
        /// <returns>
        /// HMAC hash of the specified data.
        /// </returns>
        public static byte[] HashData(byte[] buffer, byte[] validationKey)
        {
            HMACSHA1 hashSha = new HMACSHA1(validationKey);
            byte[] ret = hashSha.ComputeHash(buffer, 0, buffer.Length);
            return ret;
        }

        /// <summary>
        /// Converts a hex format string into an array of bytes.
        /// </summary>
        /// <param name="hexString">The hex string.</param>
        /// <returns>Bytes represented by the specified hex string.</returns>
        public static byte[] HexStringToByteArray(string hexString)
        {
            if ((hexString.Length & 1) == 1)
            {
                return null;
            }

            byte[] hexBytes = hexVal;
            if (hexBytes == null)
            {
                hexBytes = new byte[0x67];
                int index = hexBytes.Length;
                while (--index >= 0)
                {
                    if ((0x30 <= index) && (index <= 0x39))
                    {
                        hexBytes[index] = (byte)(index - 0x30);
                    }
                    else
                    {
                        if ((0x61 <= index) && (index <= 0x66))
                        {
                            hexBytes[index] = (byte)((index - 0x61) + 10);
                            continue;
                        }

                        if ((0x41 <= index) && (index <= 70))
                        {
                            hexBytes[index] = (byte)((index - 0x41) + 10);
                        }
                    }
                }

                hexVal = hexBytes;
            }

            byte[] outputBuffer = new byte[hexString.Length / 2];
            int num2 = 0;
            int num3 = 0;
            int length = outputBuffer.Length;
            while (--length >= 0)
            {
                int num5 = hexBytes[hexString[num2++]];
                int num6 = hexBytes[hexString[num2++]];
                outputBuffer[num3++] = (byte)((num5 << 4) + num6);
            }

            return outputBuffer;
        }

        #endregion
    }
}
